import threading
import time
from socket import socket, AF_INET, SOCK_STREAM

import wx


# 多人聊天室 服务端的实现GUI界面
class MyServerFrame(wx.Frame):
    def __init__(self, parent, title):
        # super(MyServerFrame, self).__init__(parent, title=title, size=(600, 500))
        super().__init__(parent=parent, id=1000, title=title, size=(600, 500))

        panel = wx.Panel(self)
        # box水平布局
        box = wx.BoxSizer(wx.VERTICAL)
        # 顶部布局 开始
        top_grid = wx.FlexGridSizer(wx.HORIZONTAL)
        self.btn_start = wx.Button(panel, label='启动服务', size=(200, 40))
        self.btn_save = wx.Button(panel, label='保持聊天记录', size=(200, 40))
        self.btn_stop = wx.Button(panel, label='停止服务', size=(200, 40))
        top_grid.Add(self.btn_start, 1, wx.TOP | wx.LEFT)
        top_grid.Add(self.btn_save, 1, wx.TOP | wx.Center)
        top_grid.Add(self.btn_stop, 1, wx.TOP | wx.RIGHT)
        # 顶部布局 结束
        box.Add(top_grid, 1, wx.ALIGN_CENTRE)
        # 聊天记录 和 系统消息
        self.text_chat = wx.TextCtrl(panel, size=(600, 400), style=wx.TE_MULTILINE | wx.TE_READONLY)
        box.Add(self.text_chat, 1, wx.ALIGN_CENTRE)
        # 盒子添加到面板中
        panel.SetSizer(box)
        # 存储服务器的启动状态，默认为关闭
        self.isOn = False
        # 服务器绑定ip地址和端口
        self.host_port = ('127.0.0.1', 8888)
        # 创建socket对象
        self.server_socket = socket(AF_INET, SOCK_STREAM)
        # 绑定ip地址和端口
        self.server_socket.bind(self.host_port)
        # 监听
        self.server_socket.listen(5)
        # 存储客户端的会话线程，用户名称为key ，线程为value
        self.session_dict = {}
        self.Bind(wx.EVT_BUTTON, self.click_start_button, self.btn_start)
        self.Bind(wx.EVT_BUTTON, self.click_stop_button, self.btn_stop)
        self.Bind(wx.EVT_BUTTON, self.click_save_button, self.btn_save)

    def click_stop_button(self, event):
        if self.isOn:
            self.isOn = False
            print("停止服务成功")

    def click_save_button(self, event):
        if self.isOn:
            self.text_chat.SaveFile('聊天记录.txt')
            print("保存聊天记录成功")

    def click_start_button(self, event):
        if not self.isOn:
            self.isOn = True
            server_thread = threading.Thread(target=self.start_server_work)
            # 设置为守护线程 ，守护线程会在主线程结束后自动结束
            server_thread.daemon = True
            server_thread.start()
            print("启动服务成功")

    def start_server_work(self):
        while self.isOn:
            client_socket, client_address = self.server_socket.accept()
            print(f'客户端连接成功，client_address={client_address}')
            user_name = client_socket.recv(1024).decode('utf-8')
            self.show_info_and_send('服务器通知', f'{user_name}加入聊天室',
                                    time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
            session_thread = SessionThread(client_socket, user_name, self)
            session_thread.daemon = True
            self.session_dict[user_name] = session_thread
            session_thread.start()

        self.server_socket.close()  # 当isOn为False时，会自动结束线程 服务端server_socket关闭

    def show_info_and_send(self, send_user, info, time_info):
        data = f'{send_user}:{info}\n 时间：{time_info} '
        self.text_chat.AppendText("-" * 40 + "\n" + data + "\n")
        for value in self.session_dict.values():
            if value.isOn:
                value.client_socket.send(data.encode('utf-8'))


class SessionThread(threading.Thread):
    def __init__(self, client_socket, user_name, server):
        # 调用父类的初始化方法
        threading.Thread.__init__(self)
        self.client_socket = client_socket
        self.user_name = user_name
        self.server = server
        # 会话线程是否启动，当创建线程时标识为启动
        self.isOn = True

    def run(self):
        print(f"用户{self.user_name}已经连接， 服务器启动一个会话线程")
        while self.isOn:
            data = self.client_socket.recv(1024).decode('utf-8')
            format_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            if data == 'yujikuan_disconnection':
                self.isOn = False
                self.server.show_info_and_send('服务器通知', f'{self.user_name}退出聊天室', format_time)
            else:
                self.server.show_info_and_send(self.user_name, data, format_time)
        self.client_socket.close()


if __name__ == '__main__':
    app = wx.App()
    frame = MyServerFrame(None, '聊天室服务端gui')
    frame.Show()
    app.MainLoop()
